/*
 * Copyright (c)  2016, dabing.io
 * All rights reserved.
 * OrderNextProcessReceiver.java 2017-12-03 下午3:36
 */

package com.ueboot.weishop.api.mq.receiver;

import com.rabbitmq.client.Channel;
import com.ueboot.weishop.api.component.OrderProcesser;
import com.ueboot.weishop.api.mq.config.QueuesType;
import com.ueboot.weishop.common.CacheKeys;
import com.ueboot.weishop.entity.activity.ActivityEntity;
import com.ueboot.weishop.entity.activity.CrowResultEntity;
import com.ueboot.weishop.entity.customer.CustomerInfoEntity;
import com.ueboot.weishop.entity.order.OrderEntity;
import com.ueboot.weishop.entity.order.OrderExtensionEntity;
import com.ueboot.weishop.service.activity.ActivityService;
import com.ueboot.weishop.service.activity.CrowResultService;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.customer.CustomerService;
import com.ueboot.weishop.service.order.OrderExtensionService;
import com.ueboot.weishop.service.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 描述:订单支付成功后续处理
 *
 * @author yangkui create on 2017-12-03.
 * @since 1.0
 */
@Component
@Slf4j
public class OrderNextProcessReceiver {

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderExtensionService orderExtensionService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CrowResultService crowResultService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private OrderProcesser orderProcesser;

    /***
     * 订单处理后续处理，判断是否需要开奖等操作
     * @param object
     */
    @RabbitHandler
    @RabbitListener(queues = QueuesType.ORDER_PAYED_NOTICE, containerFactory = "saveOrderTaskContainerFactory")
    public void orderSubmit(Object object, Channel channel) {
        try {
            Message m = (Message) object;
            String message = new String(m.getBody(), "UTF-8");
            if (StringUtils.isEmpty(message)) {
                log.info("消息内容为空，不处理！");
                return;
            }
            log.info("订单处理后续处理 接收到消息:{}", message);
            String orderNo = message;
            //查询订单是否属于众筹订单
            OrderEntity orderEntity = orderService.findByOrderNo(orderNo);
            //只有众筹订单才处理
            if (ActivityEntity.TYPE_CROW.equals(orderEntity.getActivityType())) {
                //生成抽奖号码
                this.generateLotteryCode(orderEntity);
            } else {
                log.info("不处理,{}", orderNo);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 生成抽奖代码，然后判断是否需要执行开奖逻辑
     */
    private void generateLotteryCode(OrderEntity orderEntity) {
        Integer count = orderEntity.getGoodsCount();
        OrderExtensionEntity extensionEntity = orderExtensionService.findByOrderNo(orderEntity.getOrderNo());
        CustomerInfoEntity customer = customerService.findByOpenId(orderEntity.getCustomerOpenId());
        ActivityEntity activityEntity = activityService.findBySn(orderEntity.getActivitySN());
        //每次中奖的抵扣金额=每期目标数量*每份价格（分）
        Integer amount = activityEntity.getCrowdUnit() * activityEntity.getCrowUnitPrice();
        StringBuilder numbers = new StringBuilder();
        for (int i = 0; i < count; i++) {
            CrowResultEntity crow = new CrowResultEntity();
            crow.setOrderNo(orderEntity.getOrderNo());
            crow.setActivityName(orderEntity.getActivityName());
            crow.setGoodsName(orderEntity.getGoodsName());
            crow.setActivityCode(orderEntity.getActivitySN());
            crow.setPeriodNum(extensionEntity.getPeriodNum());
            crow.setCustomer(customer.getName());
            crow.setCustomerVin(extensionEntity.getCustomerVin());
            crow.setCustomerMobile(customer.getMobile());
            crow.setOpenId(orderEntity.getCustomerOpenId());
            String lotteryNum = this.getLotteryNum(activityEntity.getSn(), activityEntity.getPeriodNum(), activityEntity.getCrowdUnit());
            numbers.append(lotteryNum).append(",");
            crow.setLotteryNum(lotteryNum);
            crow.setAmount(amount);
            crowResultService.save(crow);
        }
        String lotteryNums = numbers.append(",").toString().replace(",,", "");
        extensionEntity.setLotteryNums(lotteryNums);
        this.orderExtensionService.save(extensionEntity);
        //记录支付成功的数量
        String countKey = "payed:" + activityEntity.getPeriodNum();
        cacheService.incrAlreadyBuyCount(activityEntity.getSn(), countKey, count.longValue());
        //本次活动已经购买的数量
        Integer alreadyPayedCount = cacheService.getAlreadyBuyCount(activityEntity.getSn(), countKey);
        log.info("判断是否可以开奖");
        if (alreadyPayedCount >= activityEntity.getCrowdUnit()) {
            log.info("当前活动:{},当前期次:{}已经满份数，准备执行开奖逻辑。", activityEntity.getSn(), activityEntity.getPeriodNum());
            String openedKey = CacheKeys.ACT_CROW_PERIOD_OPEN_FLAG + activityEntity.getSn() + ":" + activityEntity.getPeriodNum();
            boolean putSuccess = redisTemplate.opsForValue().setIfAbsent(openedKey, "opening");
            if (!putSuccess) {
                log.info("已经由其他线程执行了当前期次开奖动作");
            } else {
                //执行开奖逻辑
                String lotteryNum = orderProcesser.executeOpenLottery(activityEntity, activityEntity.getPeriodNum());
                redisTemplate.opsForValue().set(openedKey, lotteryNum);
                log.info("期次:{}开奖完成，中奖号码为:{}", activityEntity.getPeriodNum(), lotteryNum);
            }
        } else {
            log.info("期次:{}已经支付的数量{}不满足{}，不执行开奖", activityEntity.getPeriodNum(), alreadyPayedCount, activityEntity.getCrowdUnit());
        }
    }

    /**
     * 随机生成唯一编号
     *
     * @param actSN
     * @param periodNum
     * @param crowdUnit
     * @return
     */
    private String getLotteryNum(String actSN, String periodNum, Integer crowdUnit) {
        boolean not = true;
        String lotteryNum = "";
        String key = CacheKeys.CROW_LOTTERY_NUM;
        do {
            StringBuilder sb = new StringBuilder();
            lotteryNum = String.format("%06d", RandomUtils.nextInt(crowdUnit*2));
            String lotteryNumKey = sb.append(key).append(actSN).append(":").append(periodNum).append(":").append(lotteryNum).toString();
            String retval = (String) redisTemplate.opsForValue().get(lotteryNumKey);
            if (retval == null) {
                redisTemplate.opsForValue().set(lotteryNumKey, "ok",30, TimeUnit.DAYS);
                not = false;
                log.info("actSN:{},periodNum:{},生成抽奖代码:{}", actSN, periodNum, lotteryNum);
            }

        } while (not);
        return lotteryNum;
    }

}